#ifndef _VDA_TIMER_DM_H_
#define _VDA_TIMER_DM_H_

#include <vector>
#include <cassert>
#include <map>
#include <set>
#include <string>
#include <queue>
using namespace std;

class Node_C;
class Wire_C;
class Net_C;
class Inst_C;
class LibCell_C;
class LibCellGrp_C;
class Dumper;
struct LibParserPinInfo; 
struct LibParserCellInfo;
struct LibParserLUT;
struct TimingInfo_S;
struct ParserData_S;
struct SpefConnection;
struct SpefCapacitance;
struct SpefResistance;

namespace nsLibCell
{
    enum LUTMode_E {e_fall_delay = 0, e_rise_delay, e_fall_tran, e_rise_tran};
    enum pindir_E {e_input = 0, e_output};
}
//----------------------------------------------------------------------------------------------------------//
class LibCell_C 
{
    public:
        LibCell_C(LibParserCellInfo* CellInfo);
        ~LibCell_C();
        string getName(void);
        string getFootprint(void);
        bool getPins(vector<string>& pins,nsLibCell::pindir_E dir);
        bool getPinDir(string pin,nsLibCell::pindir_E& pindir_E);
        double getLeakagePWR(void);
        double getArea(void); //assume smaller area --> slower cell
        bool is_seq(void);
        bool is_donttouch(void);
        int getNumFanin() {return _nNumFanin;}

        //pin properties
        double getCap(string pinName);
        double getMaxCap(string pinName); //TODO: only output pin consider max cap
        double getMaxCap(void);
        bool is_input(string pinName);
        bool is_clock(string pinName);

        void showAttr(void);
        
        //slow: calc delay/tran from LUT
        double getVal(string& fromPin,string& toPin,string& Sense, 
                    const double& fromPinTran,const double& toPinLoad, nsLibCell::LUTMode_E Mode); //TODO: check efficiency

        //fast: calc delay/taan from LUT
        unsigned int getArcId(string fromPin, string toPin, string Sense);
        double getVal(const uint32_t& arcId,
                    const double& fromPinTran,const double& toPinLoad, nsLibCell::LUTMode_E Mode); //TODO: check efficiency
        const LibParserLUT& getTimingLUT(string p_strFromPin, string p_strToPin, nsLibCell::LUTMode_E p_eMode) const;
    private:
        LibParserCellInfo* _CellInfo;
        //vector<LibParserTimingInfo*> _vARC;
        uint32_t _getID(string pinName); //Fail if return 0
        uint32_t _output_pin;
        //unsigned int _getID(string fromPin, string toPin, string Sense); //Fail if return 0
        int _nNumFanin;
};
//----------------------------------------------------------------------------------------------------------//
// for storing lib cell by group (footprint) and sort lib cells by power
// [0 ... MaxIdx]
class LibCellGrp_C 
{
    public:
        LibCellGrp_C(const string& footprint) { _footprint = footprint;}
        
        void sortLibCells(void);

        bool addLibCell(LibCell_C* pLibCell);
        bool getIdx(const string& LibCellName, uint32_t& idx);
        LibCell_C* getLibCell(const uint32_t& idx);
        uint32_t getMaxIdx(void) {return (_vLibCell.size()-1);}

        string getName(void) { return _footprint;}
        void showAttr(const uint32_t& idx,const bool& mark);
    
    private:
        static bool _cmpPWR(LibCell_C* a, LibCell_C* b);
        static bool _cmpArea(LibCell_C* a, LibCell_C* b);

        string _footprint;
        vector<LibCell_C*> _vLibCell;
};
//----------------------------------------------------------------------------------------------------------//
struct TimingInfo_S
{
    TimingInfo_S(): dDelayRise(0),dDelayFall(0),dTransRise(0),dTransFall(0),dSlackRise(0),dSlackFall(0) {}
    void resetRise() {dDelayRise=-1;dTransRise=-1;}
    void resetFall() {dDelayFall=-1;dTransFall=-1;}
    double dDelayRise;
    double dDelayFall;
    double dTransRise;
    double dTransFall;
    double dSlackRise;
    double dSlackFall;
};
//----------------------------------------------------------------------------------------------------------//
class Node_C
{
    public:
        enum nodeType_E {ePin = 0, eInter, ePI, ePO};
        Node_C(string p_strName); 
        Node_C(string p_strName, float p_fParasiticCap); 
        ~Node_C();
        void dump(Dumper* p_pDumper);
        //Accessor
        const int getId() const {return _nId;}
        string getName() const {return _strName;}
        virtual nodeType_E getType() const=0;
        Wire_C* getFromWire() const {return _pFromWire;}
        const vector<Wire_C*>& getToWire() const {return _vToWire;}
        virtual float getNodeCap() const=0; 
        float getParasiticCap() const {return _fParasiticCap;}
        float getEffCap() const {return _fEffCap;} 
        double getDelayRise() const {return _pTimingInfo->dDelayRise;}
        double getDelayFall() const {return _pTimingInfo->dDelayFall;}
        double getTransRise() const {return _pTimingInfo->dTransRise;}
        double getTransFall() const {return _pTimingInfo->dTransFall;}
        double getSlackRise() const {return _pTimingInfo->dSlackRise;}
        double getSlackFall() const {return _pTimingInfo->dSlackFall;}
        //Modifier - general
        void setEffCap(float p_fEffCap) {_fEffCap=p_fEffCap;}
        void setDelayRise(double p_dValue) {_pTimingInfo->dDelayRise = p_dValue;}
        void setDelayFall(double p_dValue) {_pTimingInfo->dDelayFall = p_dValue;}
        void setTransRise(double p_dValue) {_pTimingInfo->dTransRise = p_dValue;}
        void setTransFall(double p_dValue) {_pTimingInfo->dTransFall = p_dValue;}
        void setSlackRise(double p_dValue) {_pTimingInfo->dSlackRise = p_dValue;}
        void setSlackFall(double p_dValue) {_pTimingInfo->dSlackFall = p_dValue;}
        void resetTimingRise() {_pTimingInfo->resetRise();}
        void resetTimingFall() {_pTimingInfo->resetFall();}
        //Modifier - init
        void setId(int p_nId) {_nId = p_nId;}
        void setFromWire(Wire_C* p_pWire) {_pFromWire = p_pWire;}
        void addToWire(Wire_C* p_pWire) {_vToWire.push_back(p_pWire);}
        void setParasiticCap(float p_fParasiticCap) {_fParasiticCap = p_fParasiticCap;}

    private:
        int _nId;
        string _strName;
        Wire_C* _pFromWire;
        vector<Wire_C*> _vToWire;
        float _fParasiticCap;
        float _fEffCap; 
        TimingInfo_S* _pTimingInfo;
};
//----------------------------------------------------------------------------------------------------------//
class InterNode_C : public Node_C
{
    public:
        InterNode_C(string p_strName,float p_fParasiticCap) : Node_C(p_strName,p_fParasiticCap) {}
        //Accessor
        nodeType_E getType() const {return eInter;}
        float getNodeCap() const {return getParasiticCap();}
};
//----------------------------------------------------------------------------------------------------------//
class BoundaryNode_C : public Node_C
{
    public:
        BoundaryNode_C(string p_strName) : Node_C(p_strName), _pNet() {}
        ~BoundaryNode_C() {}
        void dumpTiming(Dumper* p_pDumper) const;
        virtual nodeType_E getType() const=0;
        virtual float getNodeCap() const=0; 
        Net_C* getNet() const {return _pNet;} 
        void setNet(Net_C* p_pNet) {this->_pNet = p_pNet;} 
    private:
        Net_C* _pNet;
};
//----------------------------------------------------------------------------------------------------------//
class PinNode_C : public BoundaryNode_C
{
    public:
        enum dir_E {eInput = 0, eOutput};
        PinNode_C(string p_strNodeName,string p_strPinName,Inst_C* p_pInst,dir_E p_eDir); 
        //Accessor
        string getPinName() const {return _strPinName;}
        string getInstName() const;
        string getFullName() const; 
        nodeType_E getType() const {return ePin;}
        Inst_C* getInst() const {return _pInst;}
        dir_E getDir(void) { return _eDir;}
        float getNodeCap() const; 
        //Modifier
        void setInst(Inst_C* p_pInst) {this->_pInst= p_pInst;} 
    
    private:
        //string _strInstName;
        string _strPinName;
        Inst_C* _pInst;
        dir_E _eDir;

    private:
        float getPinCap() const; 
};
//----------------------------------------------------------------------------------------------------------//
class PINode_C : public BoundaryNode_C
{
    public:
        PINode_C(string p_strName) : BoundaryNode_C(p_strName), _pDriverCell(), _fDriverTransRise(), _fDriverTransFall() {}
        //Accessor
        nodeType_E getType() const {return ePI;}
        float getNodeCap() const {return getParasiticCap();}
        LibCell_C* getLibCell() const {return _pDriverCell;}
        float getDriverTransRise() const {return _fDriverTransRise;}
        float getDriverTransFall() const {return _fDriverTransFall;}
        //Modifier - init
        void setLibCell(LibCell_C* p_pDriverCell) {_pDriverCell = p_pDriverCell;}
        void setDriverTransRise(float p_fDriverTransRise) {_fDriverTransRise = p_fDriverTransRise;}
        void setDriverTransFall(float p_fDriverTransFall) {_fDriverTransFall = p_fDriverTransFall;}
    
    private:
        LibCell_C* _pDriverCell;
        float _fDriverTransRise;
        float _fDriverTransFall;
};
//----------------------------------------------------------------------------------------------------------//
class PONode_C : public BoundaryNode_C
{
    public:
        PONode_C(string p_strName) : BoundaryNode_C(p_strName), _fLoadCap() {}
        //Accessor
        nodeType_E getType() const {return ePO;}
        float getNodeCap() const {return getParasiticCap()+_fLoadCap;}
        //Modifier - init
        void setLoadCap(float p_fLoadCap) {_fLoadCap = p_fLoadCap;}
    
    private:
        float _fLoadCap;
};
//----------------------------------------------------------------------------------------------------------//
class Wire_C
{
    public:
        Wire_C(Node_C* p_pFromNode,Node_C* p_pToNode,float p_fRes) : _pFromNode(p_pFromNode), _pToNode(p_pToNode), _fRes(p_fRes) {}
        //Accessor
        Node_C* getFromNode() const {return _pFromNode;}
        Node_C* getToNode() const {return _pToNode;}
        float getRes() const {return _fRes;}
        //Modifier - init
        void setFromNode(Node_C* p_pFromNode) {_pFromNode = p_pFromNode;}
        void setToNode(Node_C* p_pToNode) {_pToNode = p_pToNode;}

    private:
        Node_C* _pFromNode;
        Node_C* _pToNode;
        float _fRes;
};
//----------------------------------------------------------------------------------------------------------//
class Net_C
{
    public:
        Net_C(string p_strName):_strName(p_strName) {}
        string getName() const {return _strName;}
        BoundaryNode_C* getFromNode() const {return _pFromNode;}
        const vector<BoundaryNode_C*>& getToNode() const {return _vToNode;}
        const vector<Node_C*>& getNode() const {return _vNode;}
        float getLumpedCap() const {return _fLumpedCap;}
        //Modifier - init
        void setFromNode(BoundaryNode_C* p_pFromNode) {_pFromNode = p_pFromNode;}
        void addToNode(BoundaryNode_C* p_pToNode) {_vToNode.push_back(p_pToNode);}
        void addNode(Node_C* p_pNode) {_vNode.push_back(p_pNode);}
        void setLumpedCap(float p_fLumpedCap) {_fLumpedCap = p_fLumpedCap;}
        void sortNodes();
        void resetNode() {_vNode.resize(0);}

    private:
        string _strName;
        BoundaryNode_C* _pFromNode;
        vector<BoundaryNode_C*> _vToNode;
        vector<Node_C*> _vNode;
        float _fLumpedCap; //exclude cell pin capacitance
};
//----------------------------------------------------------------------------------------------------------//
class Inst_C
{
    public:
        Inst_C(string p_strName,LibCell_C* p_pLibCell); 
        void dump(Dumper* p_pDumper);
        void dumpLibCell(Dumper* p_pDumper);
        //Accessor
        const int getId() const {return _nId;}
        string getName() const {return _strName;}
        //LibParserPinInfo* getPinInfo(string p_strName);
        LibCell_C* getLibCell() const {return _pLibCell;}
        //LibCellGrp_C* getLibCellGrp() const {return _pLibCellGrp;}
        const vector<PinNode_C*>& getFromNode() const {return _vFromPinNode;}
        PinNode_C* getToNode() const {return _pToPinNode;}
        //int getTpgLvl() const {return _nTpgLvl;}
        const vector<Inst_C*>& getDriver() {return this->_vDriver;} 
        const vector<Inst_C*>& getReceiver() {return this->_vReceiver;}
        bool isSeq() const;
        
        //Modifier 
        void setLibCell(LibCell_C* p_pLibCell) {_pLibCell = p_pLibCell;}
        //void setLibCellGrp(LibCellGrp_C* p_pLibCellGrp) {_pLibCellGrp = p_pLibCellGrp;}
        //void setTpgLvl(int p_nTpgLvl) {_nTpgLvl = p_nTpgLvl;}
        
        //Modifier - init
        void setId(int p_nId) {_nId = p_nId;}
        void addFromPinNode(PinNode_C* p_pFromPinNode) {_vFromPinNode.push_back(p_pFromPinNode);}
        void setToPinNode(PinNode_C* p_pToPinNode) {_pToPinNode = p_pToPinNode;}
        void addDriver(Inst_C* p_pInst) {_vDriver.push_back(p_pInst);}
        void addReceiver(Inst_C* p_pInst) {_vReceiver.push_back(p_pInst);}
    
    private:
        int _nId;
        string _strName;
        //LibCellGrp_C* _pLibCellGrp;
        LibCell_C* _pLibCell;
        vector<PinNode_C*> _vFromPinNode;
        PinNode_C* _pToPinNode;
        vector<Inst_C*> _vDriver;
        vector<Inst_C*> _vReceiver;
        //int _nTpgLvl;
};
//----------------------------------------------------------------------------------------------------------//
class DMMgr_C
{
    public:
        class Imp_C;
        DMMgr_C(ParserData_S* p_pParserData);
        //Accessor
        const map<string,PINode_C*>&        getPINode() const;
        const map<string,PONode_C*>&        getPONode() const;
        const map<string,PinNode_C*>&       getPinNodeByMap() const;
        const vector<PinNode_C*>&           getPinNodeByVector() const;
        const map<string,InterNode_C*>&     getInterNode() const;
        const map<string,Inst_C*>&          getInstByMap() const;
        const vector<Inst_C*>&              getInstByVector() const; //in topological order, Seqs @ end
        const map<string,Net_C*>&           getNetByMap() const;
        const vector<Net_C*>&               getNetByVector() const;
        const map<string,LibCell_C*>&       getLibCell() const;
        const map<string,LibCellGrp_C*>&    getLibCellGrp() const;
        const vector<Inst_C*>&              getSeqInst() const;
        const float                         getClockPeriod() const;
        const vector<pair<string,string> >& getSize() const;
        //Dumper
        void dumpLibCell(); 
        void dumpInst(); 
        void dumpNet(); 
        void dumpNode(); 
        void dumpTiming(); 
        void dumpSize(); 

    private:
        Imp_C* _pImp;
};
//----------------------------------------------------------------------------------------------------------//

#endif
